home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Meeting Pearls 4
/
Meeting Pearls Vol. IV (1996)(GTI - Schatztruhe)[!].iso
/
Pearls
/
midi
/
misc
/
Midi2TeX
/
src
/
tp_midi.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1992-11-20
|
26KB
|
704 lines
UNIT TP_MIDI;
INTERFACE
uses DOS,
TP_decl,
TP_Misc,
TP_debug,
TP_heap1,
TP_M2TF2;
Procedure InsertRest(VAR ThisTrack : TrackRecord);
Procedure ReadMetaEvent( VAR ThisTrack : TrackRecord);
Function EndOfTrackReached(VAR ThisTrack:TrackRecord):boolean;
Procedure WriteTexHeader;
Function GetPortees: String;
Function StaffIndex(No : Byte): String;
Procedure Quantize(VAR N : NoteRecPoint);
Procedure ReadDeltaTime(VAR ThisTrack : TrackRecord);
Procedure ReadEvent(VAR ThisTrack : TrackRecord);
Procedure ChangeContext(N : NoteRecPoint);
IMPLEMENTATION
(********************************************)
Function StaffIndex(No : Byte): String;
(********************************************)
Begin
Case No OF
1 : StaffIndex:='i';
2 : StaffIndex:='ii';
3 : StaffIndex:='iii';
4 : StaffIndex:='iv';
5 : StaffIndex:='v';
6 : StaffIndex:='vi';
7 : StaffIndex:='vii';
8 : StaffIndex:='viii';
9 : StaffIndex:='ix';
10 : StaffIndex:='x';
Else
ErrorExit(8);
End; (* case *)
End;
(**********************************************)
Function GetPortees: String;
(**********************************************)
VAR TmpSTr : String;
curinstr,
curtr,staff,
StartStaff,
nStaffsInInstr : Byte;
StartFound : Boolean;
Begin
TmpStr:='';
StartFound:=FALSE;
For curinstr:=1 to 1 Do (* this version only supports one instrument *)
Begin
staff:=1;
For curtr:=ntracks downto 1 do
With TrackArray[TrackOrder[curtr]] Do
Begin
If Not Skip Then
Begin
If NOT StartFound Then
Begin
If Instrument Then
Begin
StartStaff:=Staff;
StartFound:=TRUE;
nStaffsInInstr:=1;
End
End
Else
Begin
If Instrument Then INC(nStaffsInInstr);
End;
Inc(Staff);
End
End; (* With *)
TmpStr:='\nbportees'+StaffIndex(StartStaff)+'='+B2S(nStaffsInInstr);
End; (* for next curinstr *)
GetPortees:=TmpStr;
End;
(**********************************************)
Procedure WriteTexHeader;
(**********************************************)
{$IFDEF ST}
Var Year,Month,Day,DoW : Integer;
{$ENDIF}
{$IFDEF PC}
Var Year,Month,Day,DoW : Word;
{$ENDIF}
Begin
GetDate(Year,Month,Day,DoW);
WriteLn(TexFile,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%');
WriteLn(TexFile,'% TEX translation of MIDI File :');
With MidiFileName Do
WriteLn(TexFile,'% ',n,e);
WriteLn(TexFile,'% ');
WriteLn(TexFile,'% Written by Hans Kuykens');
WriteLn(TeXFile,'% this translation of date : '+W2S(Day)+'-'+W2S(Month)+'-'+W2S(Year));
WriteLn(TexFile,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%');
WriteLn(TexFile,'\input musicnft');
WriteLn(TexFile,'\input musictex');
WriteLn(TexFile,'\input musicadd');
WriteLn(TexFile,'\input musictrp');
WriteLn(TexFile,'\normal');
If SizingChanged Then
Begin
WriteLn(TexFile,'\hsize '+I2S(ScoreWidth div 10)+'mm \vsize '+I2S(ScoreHeight div 10)+'mm');
WriteLn(TexFile,'\musicsize='+I2S(MusicSize));
WriteLn(TeXFile,'\elemskip=',I2S(Round(Elemskip/PT)),'pt%');
End;
If ninstruments>0 Then
Begin
WriteLn(TexFile,'\def\nbinstruments{'+B2S(ntracks-NoOfSkips-(nTracksInInstr-1))+'}');
WriteLn(TeXFile,GetPortees);
End
Else
WriteLn(TexFile,'\def\nbinstruments{'+B2S(ntracks-NoOfSkips)+'}');
(*WriteLn(TexFile,'\signaturegenerale{0}'); *)
WriteLn(TexFile,'\generalsignature{'+SI2S(PieceContr.KeySign)+'}\relax');
WriteLn(TeXFile,'%\centerline{\enorme PUT A NAME HERE and remove %}');
With TeXFileName DO
WriteLn(TeXFile,'\medskip\centerline{\moyen '+n+e+'}');
WriteLn(TeXFile,'\rightline{translation by MIDI2TeX}');
WriteLn(TeXFile,'\rightline{by H.J.P. Kuykens}');
End; (* WriteTexHeader *)
(********************************************)
Procedure FinishTeXHeader(num,den : Byte);
(********************************************)
VAR i,j,k : Byte;
(*-----------------------------------------------*)
function FindStaff(ThisTrack : Integer):Integer;
(*-----------------------------------------------*)
(* Watch it ! If the track is in an instrument than the parameter string *)
(* must be altered of cleftoks# *)
VAR i,j : Integer;
Begin
i:=ntracks;
j:=1;
While TrackOrder[i]<>ThisTrack Do
Begin
If NOT TrackArray[TrackOrder[i]].SKIP Then Inc(J);
Dec(i);
End;
FindStaff:=j;
End; (* FindStaff *)
(*-----------------------------------------------*)
function FindClefStaff(ThisTrack : Integer):String;
(*-----------------------------------------------*)
VAR i,j ,k : Integer;
C : String[2];
Begin
i:=ntracks;
j:=1;
k:=1;
Str(Ord(TrackArray[TrackOrder[ThisTrack]].Clef),C);
While TrackOrder[i]<>ThisTrack Do
Begin
If NOT TrackArray[TrackOrder[i]].SKIP Then
If TrackArray[TrackOrder[i]].Instrument Then
Inc(k)
ELse
Inc(J);
Dec(i);
End;
case k of
1 : FindClefStaff:='\cleftoks'+StaffIndex(j)+'{{'+C+'}{0}{0}{0}}';
2 : FindClefStaff:='\cleftoks'+StaffIndex(j)+'{{0}{'+C+'}{0}{0}}';
3 : FindClefStaff:='\cleftoks'+StaffIndex(j)+'{{0}{0}{'+C+'}{0}}';
4 : FindClefStaff:='\cleftoks'+StaffIndex(j)+'{{0}{0}{0}{'+C+'}}';
Else
Warning('Something wrong with cleftoks#, check it out !');
FindClefStaff:='\cleftoks??';
End;
End; (* FindClefStaff *)
Begin
WriteLn(TexFile,'\generalmeter{\meterfrac{',Num,'}{',Power(2,Den),'}}%');
(* determine clefs *)
For i:=1 to ntracks do
Begin
If TrackArray[i].Clef>VIOLIN Then
Begin
WriteLn(TeXFile,FindClefStaff(i));
End;
End;
WriteLn(TexFile,'%\raggedlinestrue % uncomment for ragged right lines ');
WriteLn(TeXFile,'%\relativeaccidentals');
WriteLn(TexFile,'\debutmorceau');
TeXHeaderFinished:=TRUE;
End;
(********************************************)
Procedure ChangeContext(N : NoteRecPoint);
(********************************************)
Begin
With N^ DO
Case Event Of
KEYSIGN : Begin
WriteLn(TeXFile,'\signaturegenerale{'+B2S(NoteVal)+'}\changecontext%');
With PieceContr DO
Begin
KeySign:=NoteVal;
Minor:=Velocity;
End;
End;
SIGNATURE : Begin
WriteLn(TexFile,'\generalmeter{\meterfrac{',Noteval,'}{',Power(2,Velocity),'}}%');
WriteLn(TeXFile,'\changecontext%');
With PieceContr DO
Begin
Num:=NoteVal;Den:=Velocity;
TicksPerMeasure:=4*Division*Num div Power(2,Den);
If NOT PartOverRule Then
PartTime:=TicksPerMeasure div Num;
nparts:=TicksPerMeasure div PartTime;
Twindow:=Division div 16;
End;
End;
End; (* case *)
End;
(*****************************************************)
Procedure Quantize(VAR N : NoteRecPoint); (* Still needs updating !!! *)
(*****************************************************)
VAR dt : Longint;
T : MeasureTime;
Begin
With N^ Do
Begin
dt:=TimeDiff(EndTime,StartTime);
if dt>QuantTime Then
Begin
(* quantize notelength first *)
dt:=QuantTime*Round(dt/QuantTime);
SetTime(T,0,dt);
(* quantize start time and end time*)
StartTime.MPart:=QuantTime*Round(StartTime.MPart/QuantTime);
AddTime(StartTime,T,EndTime);
End
End;
End;
(*******************************************************)
Procedure ReadDeltaTime(VAR ThisTrack : TrackRecord);
(*******************************************************)
VAR delta : LONGINT ;
Begin
With ThisTrack DO
Begin
OldOldTime:=OldTime;
OldTime:=CurTime;
delta:=ReadVarLen(FilRec);
(* WriteDebugInfo('read deltatime :'+LI2S(delta)); *)
With CurTime DO
IF PieceContr.TicksPerMeasure=0 Then
INC(Mpart,delta)
Else
Begin
INC(MPart,delta);
WITH PieceContr DO
IF MPart>=TicksPerMeasure Then
BEGIN
Measure:=Measure+ (MPart div TicksPerMeasure);
MPart:=MPart MOD TicksPerMeasure;
End;
End;
End;
End;
(******************************************************)
Procedure InsertRest(VAR ThisTrack : TrackRecord);
(******************************************************)
VAR N : NoteRecPoint;
TmpTime1,
TmpTime2 : MeasureTime;
Begin
SetTime(TmpTime1,MeasureCount,0);
SetTime(TmpTime2,MeasureCount+1,0);
With ThisTrack Do
Begin
N:=GetFreeNote;
N^.Event:=REST;
(*
If (TimeDiff(TmpTime2,LastNoteOffTime)>0) AND
(TimeDiff(TmpTime1,LastNoteOffTime)<=0) Then
N^.STartTime:=LastNoteOffTime
Else
N^.STartTime:=TmpTime1;
If TimeDiff(TmpTime2,CurTime)<0 Then
N^.EndTime:=TmpTime2
Else
N^.EndTime:=CurTime;
*)
N^.EndTime:=CurTime;
N^.STartTime:=LastNoteOffTime;
Append(NoteList,N);
WriteDebugInfo('Inserted Rest between '+W2S(N^.StartTime.Measure)+':'+LI2S(N^.StartTime.MPart)+
' and '+W2S(N^.EndTime.Measure)+':'+LI2S(N^.EndTime.MPart));
End;
End;
(******************************************************)
Procedure ReadNoteOn(MidCode : Byte;
VAR ThisTrack : TrackRecord);
(******************************************************)
VAR N,P : NoteRecPoint;
dt : LongInt;
TmpVal,TmpVel : Byte;
Begin
With ThisTrack Do
Begin
TmpVal:=ReadByte(FilRec);
TmpVel:=ReadByte(FilRec); (* if TmpVel=0 Than it is a Note OFF ! *)
If TmpVel>0 Then
Begin
If (NotesSounding=0) Then
Begin
dt:=TimeDiff(CurTime,LastNoteOffTime);
If Quantizing Then
Begin
If dt>QuantTime Then (* only insert rest if longer than QuantTime *)
InsertRest(ThisTrack)
End
Else
If dt>=(PieceContr.Division div 4) Then (* only insert rest if longer than 1/16th note *)
InsertRest(ThisTrack)
End
Else (* There are notes sounding, check if same note is already on *)
Begin
FirstNote(NoteList,N);
P:=NIL;
while N<>P do
Begin
If P=NIL then P:=N;
If (N^.NoteVal=TmpVal) AND (N^.Event=NOTEON) Then (* close this note down *)
Begin
N^.EndTime:=CurTime;
N^.Event:=NOTEOFF;
LastNoteOffTime:=CurTime;
If NotesSounding>0 Then
Dec(NotesSounding);
WriteDebugInfo('Closed down a double note');
End;
NextNote(N,N);
End
End;
N:=GetFreeNote;
Append(NoteList,N);
With N^ Do
Begin
MidiChnl:=MidCode MOD 15;
NoteVal:=TmpVal;
Velocity:=TmpVel;
Event:=NOTEON;
StartTime:=CurTime;
SetTime(EndTime,1000,0); (* set EndTime to infinity *)
WriteDebugInfo((*W2S(NoteArPoint)+*)'NoteOn : '+B2S(NoteVal)+' Vel : '+B2S(velocity)+
' at '+W2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
End;
Inc(NotesSounding);
End
Else (* the Velocity value is 0 set Note Off *)
Begin
WriteDebugInfo('NoteOff : '+B2S(TmpVal)+
' at '+W2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
If NoteList.Size>0 Then
Begin
LastNote(NoteList,N); (* dit gaat soms fout ... ? *)
FirstNote(NoteList,P); (* een maat kan beginnen met een NoteOff !!!! *)
While (NOT EqualsNote(N,TmpVal)) AND (N<>P) Do
PrevNote(N,N);
if N=NIL Then
ErrorExit(6)
else
if NOT EqualsNote(N,TmpVal) Then
WriteDebugInfo('Could not find note-ON for this note-OFF')
else
Begin
If N^.Event=NOTEON Then
Begin
N^.EndTime:=CurTime;
N^.Event:=NOTEOFF;
End
Else
WriteDebugInfo('Note was already OFF, probably a double note...');
End;
LastNoteOffTime:=CurTime;
If NotesSounding>0 Then
Dec(NotesSounding);
End (* If NoteList.Size > 0 *)
Else
WriteDebugInfo('There can`t be a NoteOff if there are no notes at all !');
End; (* Set Note Off *)
End; (* With ThisTrack *)
End; (* ReadNoteOn *)
(******************************************************)
Procedure ReadNoteOff(MidCode : Byte;
VAR ThisTrack : TrackRecord);
(******************************************************)
VAR N,P : NoteRecPoint;
MidiChnl,
velo,
Note : Byte;
Begin
With ThisTrack Do
Begin
MidiChnl:=MidCode MOD 15;
Note:=ReadByte(FilRec);
velo:=ReadByte(FilRec);
WriteDebugInfo('NoteOff : '+B2S(Note)+
' at '+W2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
If NoteList.Size>0 Then
Begin
LastNote(NoteList,N); (* dit gaat soms fout ... ? *)
FirstNote(NoteList,P); (* een maat kan beginnen met een NoteOff !!!! *)
While (NOT EqualsNote(N,Note)) AND (N<>P) Do
PrevNote(N,N);
if N=NIL Then
ErrorExit(6)
else
if NOT EqualsNote(N,Note) Then
WriteDebugInfo('Could not find note-ON for this note-OFF')
else
Begin
If N^.Event=NOTEON Then
Begin
N^.EndTime:=CurTime;
N^.Event:=NOTEOFF;
End
Else
WriteDebugInfo('Note was already OFF, probably a double note...');
End;
LastNoteOffTime:=CurTime;
If NotesSounding>0 Then
Dec(NotesSounding);
End (* If NoteList.Size > 0 *)
Else
WriteDebugInfo('There can`t be a NoteOff if there are no notes at all !');
End; (* with this track *)
End; (* ReadNoteOff *)
(******************************************************)
Procedure ReadMetaText(Len : Byte;
VAR ThisTrack : TrackRecord);
(******************************************************)
VAR N : NoteRecPoint;
Begin
With ThisTrack Do
Begin
N:=GetFreeNote;
Append(NoteList,N);
With N^ Do
Begin
Event:=TXT;
If MaxAvail>SizeOf(String20Type) Then
GetMem(MetaTxt,SizeOf(String20Type))
Else
ErrorExit(9);
StartTime:=CurTime;
EndTime:=CurTime;
EndTime.Measure:=EndTime.Measure+1;
MetaTxt^:=ReadString(FilRec,Len);
WriteDebugInfo('MetaText :' + MetaTxt^ + ' at '+I2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
End;
End;
End; (* ReadText *)
(******************************************************)
Procedure ReadDamper(MidiCode : byte;
VAR ThisTrack : TrackRecord);
(******************************************************)
VAR N : NoteRecPoint;
Begin
With ThisTrack Do
Begin
N:=GetFreeNote;
Append(NoteList,N);
With N^ Do
Begin
Event:=PEDAL;
Velocity:=ReadByte(ThisTrack.FilRec);
StartTime:=CurTime;
EndTime:=CurTime;
EndTime.Measure:=EndTime.Measure+1;
WriteDebugInfo('Pedal : at '+I2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
End;
End;
End; (* ReadDamper *)
(**********************************************************)
Procedure ReadMetaEvent( VAR ThisTrack : TrackRecord);
(**********************************************************)
VAR
DumStr : String[255];
i,
DumInt : Integer;
DumByte,
MetaType : Byte;
MetaByteCnt : Word;
MetaLength : LongInt;
N : NoteRecPoint;
Begin
With ThisTrack Do
Begin
MetaType:=ReadByte(FilRec);
MetaLength:=ReadVarLen(FilRec);
WriteDebugInfo(' Read Meta event type : '+B2S(MetaType)+' of '+
LI2S(MetaLength)+' bytes');
MetaByteCnt:=0;
case MetaType Of
0 : Begin
DumByte:=ReadByte(FilRec);
DumInt:=ReadInteger(FilRec);
End;
1..7: Begin (* Text events *)
(* DumStr:=ReadString(FilRec,MetaLength); *)
ReadMetaText(MetaLength,ThisTrack);
End;
32 : DumByte:=ReadByte(FilRec); (* MIDI Chnl Prefix *)
47 : Begin EndOfTrackRead:=TRUE; End; (* End of Track *)
81 : Begin (* set tempo *)
With PieceContr Do
Begin
Tempo:=ReadByte(FilRec);Tempo:=Tempo SHL 8;
Tempo:=Tempo+ReadByte(FilRec);Tempo:=Tempo SHL 8;
Tempo:=Tempo+ReadByte(FilRec);
End;
End;
84 : Begin (* SMPTE OffSet *)
DumByte:=ReadByte(FilRec);DumByte:=ReadByte(FilRec);
DumByte:=ReadByte(FilRec);DumByte:=ReadByte(FilRec);
DumByte:=ReadByte(FilRec);
End;
88 : Begin (* Time Sign *)
If TeXHeaderFinished then (* store the value on the note list *)
Begin
N:=GetFreeNote;
Append(NoteList,N);
With N^ Do
Begin
Event:=SIGNATURE;
NoteVal:=ReadByte(FilRec); (* NUM *)
Velocity:=ReadByte(FilRec); (* DEN *)
DumByte:=ReadByte(FilRec);DumByte:=ReadByte(FilRec);
StartTime:=CurTime;
EndTime:=CurTime;
WriteDebugInfo('Signature : ' + B2S(NoteVal)+'/'+ I2S(Power(2,Velocity)) +' at '+
I2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
End
End
Else
With PieceContr Do
Begin
Num:=ReadByte(FilRec);Den:=ReadByte(FilRec);
FinishTeXHeader(Num,Den);
DumByte:=ReadByte(FilRec);DumByte:=ReadByte(FilRec);
TicksPerMeasure:=4*Division*Num div Power(2,Den);
If NOT PartOverRule Then
PartTime:=TicksPerMeasure div Num
Else
PartTime:=4*Division div PartType;
nparts:=TicksPerMeasure div PartTime;
Twindow:=Division div 16;
If Quantizing Then QuantTime:=Division*4 div QuantTime;
WriteDebugInfo('4*'+I2S(Division)+'*'+B2S(Num)+' div '+
B2S(Den)+' = '+W2S(TicksPerMeasure)+' Ticks per measure');
End;
End;
89 : Begin (* Key signature *)
If TeXHeaderFinished then (* store the value on the note list *)
Begin
N:=GetFreeNote;
Append(NoteList,N);
With N^ Do
Begin
Event:=KEYSIGN;
NoteVal:=ReadByte(FilRec); (* KeySign *)
Velocity:=ReadByte(FilRec); (* Minor *)
StartTime:=CurTime;
EndTime:=CurTime;
WriteDebugInfo('Keysign : ' + B2S(NoteVal) + ' at '+
I2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
End
End
Else
With PieceContr DO
Begin
KeySign:=ReadByte(FilRec);
Minor:=ReadByte(FilRec);
If KeySign>0 Then
WriteDebugInfo('KeySignature : '+B2S(KeySign)+' sharps ')
Else
WriteDebugInfo('KeySignature : '+B2S(KeySign)+' flats ');
End; (* with *)
End;
127 : Begin (* specials.... *)
For i:=1 to MetaLength Do DumByte:=ReadByte(FilRec);
End;
End; (* case *)
End;
End; (* ReadMetaEvent *)
(*****************************************************)
Procedure ReadEvent(VAR ThisTrack : TrackRecord);
(*****************************************************)
VAR DumByte,
MidiCode : Byte;
Begin
With ThisTrack Do
Begin
MidiCode:=ReadByte(FilRec);
case MidiCode Of
$90..$9F : Begin ReadNoteOn(MidiCode,ThisTrack); StatusByte:=MidiCode; End;
$80..$8F : Begin ReadNoteOff(MidiCode,ThisTrack); StatusByte:=MidiCode; End;
$FF : Begin ReadMetaEvent(ThisTrack); StatusByte:=MidiCode; End;
$A0..$AF : Begin For i:=1 to 2 Do DumByte:=ReadByte(FilRec);
StatusByte:=MidiCode; End;(* polypress. *)
$B0..$BF : Begin
DumByte:=ReadByte(FilRec);
case DumByte of
$40 : ReadDamper(MidiCode,ThisTrack); { this is a damper pedal }
Else
DumByte:=ReadByte(FilRec);
End; { case }
StatusByte:=MidiCode;
End;(* control change *)
$C0..$CF : Begin DumByte:=ReadByte(FilRec); StatusByte:=MidiCode; End;(* progr. change *)
$D0..$DF : Begin DumByte:=ReadByte(FilRec);
StatusByte:=MidiCode; End;(* channel pressure *)
$E0..$EF : Begin For i:=1 to 2 Do DumByte:=ReadByte(FilRec); StatusByte:=MidiCode; End;(* pitch wheel *)
$F8 : Begin (* do nothing *) End; (* timing clock *)
$F0 : Begin
Repeat (* SysEx code *)
DumByte:=ReadByte(FilRec);
until DumByte=$F7;
StatusByte:=00;
End;
$F1 : DumByte:=ReadByte(FilRec);(* quarter frame *)
Else (* WriteDebugInfo(' Unknown MidiEvent, type : '+B2S(MidiCode)); *)
(* This is a running status *)
Begin
RestoreLastRead(FilRec); (* This will NOT work ALWAYS !!! *)
case StatusByte Of
$90..$9F : ReadNoteOn(StatusByte,ThisTrack);
$80..$8F : ReadNoteOff(StatusByte,ThisTrack);
$FF : ReadMetaEvent(ThisTrack);
$A0..$AF : For i:=1 to 2 Do DumByte:=ReadByte(FilRec);
$B0..$BF : For i:=1 to 2 Do DumByte:=ReadByte(FilRec);
$C0..$CF : DumByte:=ReadByte(FilRec);
$D0..$DF : DumByte:=ReadByte(FilRec);
$E0..$EF : For i:=1 to 2 Do DumByte:=ReadByte(FilRec);
$F8 : Begin (* do nothing *) End; (* timing clock *)
$F0 : Repeat (* SysEx code *)
DumByte:=ReadByte(FilRec);
until DumByte=$F7;
$F1 : DumByte:=ReadByte(FilRec);(* quarter frame *)
End; (* case *)
End;
end;
End;
End; (* ReadEvent *)
(**************************************************************)
Function EndOfTrackReached(VAR ThisTrack:TrackRecord):boolean;
(*************************************************************)
Begin
With ThisTrack Do
If EndOfTrackRead AND
(SpillList.Size=0) AND
(NoteList.Size=0) Then
EndOfTrackReached:=TRUE
Else
EndOfTrackReached:=FALSE;
End;
Begin
End.